home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / workman_stubs.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  47KB  |  1,973 lines

  1. /*
  2.  * @(#)workman_stubs.c    1.134    4/8/94
  3.  *
  4.  * workman_stubs.c - Notify and event callback function stubs.
  5.  */
  6.  
  7. static char *ident = "@(#)workman_stubs.c    1.134\t4/8/94";
  8.  
  9. #include <stdio.h>
  10. #include <sys/param.h>
  11. #include <sys/types.h>
  12. #include <signal.h>
  13. #include <xview/xview.h>
  14. #include <xview/panel.h>
  15. #include <xview/textsw.h>
  16. #include <xview/xv_xrect.h>
  17. #include <xview/screen.h>
  18. #include <xview/notice.h>
  19. #include <xview/defaults.h>
  20. #include "workman_ui.h"
  21. #include "struct.h"
  22.  
  23. /* Linux doesn't have a SIGEMT */
  24. #ifndef SIGEMT
  25. #define SIGEMT SIGUNUSED
  26. #endif
  27.  
  28. void    quit();
  29. void    continued();
  30. void    setup_itimer();
  31. void    init_stats();
  32. void    avoid_track();
  33. void    keep_settings();
  34. void    cd_volume();
  35. void    keep_cd_open();
  36. void    figure_volume();
  37. void    set_default_volume();
  38. void    text_event_p();
  39. void    next_stopmode();
  40. void    new_cd_inserted();
  41. char *    listentry();
  42. char *    trackname();
  43. int *    get_playlist();
  44. void    make_initial_playlist();
  45. void    kill_stats();
  46. void    start_repeating();
  47. void    add_playlist();
  48. int    switch_playlists();
  49. void    stop_repeating();
  50. Notify_value check_open(), byebye(), sigusr1(), sigusr2(), sigquit(),
  51.     sigttin(), sigttou(), sigemt();
  52. void    window1_button2_notify_callback(),
  53.     popup1_buttonpl_notify_callback(),
  54.     window1_button4_notify_callback(),
  55.     window1_button3_notify_callback();
  56. Panel_item    quitbutton;
  57. char    *getenv(), *WMstrdup();
  58.  
  59. char    *pidfile = "/tmp/.wm_pid";
  60. char *    empty = "";
  61. extern char *cd_device;
  62.  
  63. Rect    *track_rect = NULL;
  64. Xv_Notice wannasave, mountedfs;
  65. int    confirmsave;
  66. int    add_height, small_height;
  67. int    min_lines = -1;
  68. int    dont_retry = 0;
  69. void    (*text_event_handler)();
  70.  
  71. window1_objects    *Workman_window1;
  72. popup1_objects    *Workman_popup1;
  73. about_objects    *Workman_about;
  74. goodies_objects    *Workman_goodies;
  75. plpopup_objects    *Workman_plpopup;
  76.  
  77. extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen,
  78.     cur_ntracks, cur_lasttrack, cur_firsttrack, cur_listno;
  79. extern enum cd_modes cur_cdmode;
  80. extern int cur_frame;
  81. extern int cd_fd;
  82. extern int exit_on_eject, suppress_locking;
  83. extern int found_in_db, found_in_rc;
  84. extern int min_volume, max_volume;
  85. extern int intermittent_dev;
  86. extern char *cur_cdname, *cur_artist, cur_contd, cur_avoid;
  87. int cur_playnew = -1;
  88. int displayed_track = -1;        /* Track whose info is onscreen */
  89. int pop_track = 0;            /* Track being edited in popup */
  90. int *pop_list = NULL;            /* Our notion of the playlist */
  91. int pop_listsize = 0;            /* List size, including 0 */
  92. int pl_item = -1;            /* Playlist item selected */
  93. int pl_listnum = -1;            /* Number of current playlist */
  94. int my_artist = 0, my_cdname = 0;
  95. int num_names = 0, num_nalloc = 0;
  96. int cur_balance = 10;
  97. int manual_volume = 0;        /* Has the user changed the volume by hand? */
  98. int cur_stopmode = -1;
  99. int mark_a = 0, mark_b = 0;
  100. int window_is_open;
  101. int was_repeating = 0;
  102. int info_modified = 0;
  103. int show_titles = 1;
  104. #if defined(hpux) || defined(__bsdi__)
  105. int dismiss_button = 1;
  106. #else
  107. int dismiss_button = 0;
  108. #endif
  109.  
  110. Attr_attribute    INSTANCE;
  111.  
  112. #ifdef __sony_news
  113. /* XXX -- anyone know why XView messes up on NEWS without this? */
  114. static int error_handler(void *d, void *e) { return (0); }
  115. #endif
  116.  
  117. main(argc, argv)
  118.     int    argc;
  119.     char    **argv;
  120. {
  121.     int        c;
  122.     FILE        *fp;
  123.     char        *name;
  124.         extern char     *optarg, *rcfile, *dbfiles;
  125.     extern int    keep_open;
  126.  
  127. #ifdef SVR4
  128.         if (setreuid(-1, getuid()) < 0)
  129.         {
  130.                 perror("setreuid");
  131.                 exit(-1);
  132.         }
  133. #endif
  134.         
  135.     /*
  136.      * Initialize XView.
  137.      */
  138.     xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
  139. #ifdef __sony_news
  140.     XSetErrorHandler(&error_handler);
  141. #endif
  142.     INSTANCE = xv_unique_key();
  143.  
  144.     /*
  145.      * Initialize the list of database locations.  Precedence is
  146.      * command-line then resource then environment.
  147.      */
  148.     rcfile = getenv("WORKMANRC");
  149.     rcfile = defaults_get_string("workman.db.personal",
  150.         "Workman.Db.Personal", rcfile);
  151.     if (rcfile)
  152.         rcfile = WMstrdup(rcfile);
  153.     dbfiles = getenv("WORKMANDB");
  154.     dbfiles = defaults_get_string("workman.db.shared",
  155.         "Workman.Db.Shared", dbfiles);
  156.     if (dbfiles)
  157.         dbfiles = WMstrdup(dbfiles);
  158.  
  159.     while ((c = getopt(argc, argv, "s:p:dc:ol:eXnbV:hCD:")) != EOF)
  160.         switch (c) {
  161.         case 'p':
  162.             pidfile = optarg;
  163.             break;
  164.         case 'b':
  165.             dismiss_button = ! dismiss_button;
  166.             break;
  167.         case 'd':
  168.             if (! show_titles--)
  169.                 min_lines = 0;
  170.             break;
  171.         case 'e':
  172.             if (dont_retry == 0)
  173.                 dont_retry = 2;
  174.             else
  175.                 dont_retry = 1;
  176.             break;
  177.         case 'c':
  178.             cd_device = optarg;
  179.             break;
  180.         case 'o':
  181.             keep_open = 0;
  182.             break;
  183.         case 'l':
  184.             min_lines = atoi(optarg);
  185.             break;
  186.         case 'X':
  187.             exit_on_eject = 1;
  188.             break;
  189.         case 'n':
  190.             suppress_locking = 1;
  191.             break;
  192.         case 'V':
  193.             min_volume = atoi(optarg);
  194.             break;
  195.         case 'C':
  196.             intermittent_dev = 1;
  197.             break;
  198.         case 's':
  199.             send_signal(optarg, pidfile);
  200.             break;
  201.         case 'D':
  202.             dbfiles = optarg;
  203.             break;
  204.         case 'h':
  205.         default:
  206.             fprintf(stderr,
  207. "usage: %s [-bCdehnoX] [-s cmd] [-p file] [-c device] [-l N] [-V n]\n\
  208. \t\t[-s back|fwd|pause|play|stop|eject|mute|go] [-D file]\n\
  209.   -b  put dismiss buttons on windows\n\
  210.   -c  use alternate device (default = %s)\n\
  211.   -d  don't display title information\n\
  212.   -D  filename(s) of global database\n\
  213.   -e  don't check for CD insertion when no CD is present\n\
  214.   -h  display this message\n", argv[0], cd_device);
  215.             fprintf(stderr,
  216. "  -l  leave room for at least N lines of track title\n\
  217.   -n  don't use file locking when updating database (dangerous)\n\
  218.   -o  don't run background job to keep device open (Solaris 2.0/2.1)\n\
  219.   -p  write process ID to another file (default = %s)\n\
  220.   -s  send command to running WorkMan\n\
  221.   -C  close device after eject\n\
  222.   -V  minimum volume setting (default = %d)\n\
  223.   -X  exit when CD is ejected\n", pidfile, min_volume);
  224.             exit(1);
  225.         }
  226.  
  227.     /*
  228.      * Initialize the user-interface components.
  229.      */
  230.     Workman_window1 = window1_objects_init(NULL, NULL);
  231.     Workman_popup1 = popup1_objects_init(NULL, Workman_window1->window1);
  232.     Workman_about = about_objects_init(NULL, Workman_window1->window1);
  233.     Workman_goodies = goodies_objects_init(NULL, Workman_window1->window1);
  234.     Workman_plpopup = plpopup_objects_init(NULL, Workman_window1->window1);
  235.  
  236.     /* Cook the database filenames, or construct them if none were given. */
  237.     split_workmandb();
  238.  
  239.     if (keep_open)
  240.         if (fork() == 0)
  241.             keep_cd_open();
  242.         else
  243.             wait(NULL);
  244.  
  245.     /*
  246.      * Fill up the PID-file.
  247.      */
  248.     fp = fopen(pidfile, "w");
  249.     if (fp != NULL)
  250.     {
  251.         fprintf(fp, "%d\n", getpid());
  252.         fflush(fp);
  253.         fchmod(fileno(fp), 0666);
  254.         fclose(fp);
  255.     }
  256.     else
  257.     {
  258.         fprintf(stderr, "Warning: ");
  259.         perror(pidfile);
  260.     }
  261.  
  262.     if (dismiss_button)
  263.     {
  264.         Panel_item    button;
  265.         int        spacing;
  266.  
  267.         xv_create(Workman_plpopup->controls5, PANEL_BUTTON,
  268.             XV_X, 10, XV_Y, (int) xv_get(Workman_plpopup->delete,
  269.             XV_Y), PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  270.             popup1_buttonpl_notify_callback, NULL);
  271.         xv_create(Workman_popup1->controls2, PANEL_BUTTON,
  272.             XV_X, 10, XV_Y, (int) xv_get(Workman_popup1->buttonpl,
  273.             XV_Y), PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  274.             window1_button2_notify_callback, NULL);
  275. #define ip Workman_window1
  276.         /* Squish the main window buttons down some. */
  277.         quitbutton = xv_create(ip->controls1, PANEL_BUTTON,
  278.             PANEL_LABEL_STRING, "Quit", PANEL_NOTIFY_PROC,
  279.             quit, NULL);
  280.         xv_set(ip->button3, PANEL_LABEL_STRING, "About", NULL);
  281.         xv_set(ip->button2, PANEL_LABEL_STRING, "CD Info", NULL);
  282.         xv_set(ip->button4, PANEL_LABEL_STRING, "Goodies", NULL);
  283.         spacing = ((int) xv_get(ip->controls1, XV_WIDTH) - (
  284.             (int) xv_get(ip->button2, XV_WIDTH) +
  285.             (int) xv_get(ip->button3, XV_WIDTH) +
  286.             (int) xv_get(ip->button4, XV_WIDTH) +
  287.             (int) xv_get(quitbutton, XV_WIDTH))) / 5;
  288.         xv_set(ip->button3, XV_X, spacing, NULL);
  289.         xv_set(ip->button2, XV_X, (int) xv_get(ip->button3, XV_WIDTH) +
  290.             (int) xv_get(ip->button3, XV_X) + spacing, NULL);
  291.         xv_set(ip->button4, XV_X, (int) xv_get(ip->button2, XV_WIDTH) +
  292.             (int) xv_get(ip->button2, XV_X) + spacing, NULL);
  293.         xv_set(quitbutton, XV_Y, (int) xv_get(Workman_window1->button2,
  294.             XV_Y), XV_X, (int) xv_get(ip->controls1, XV_WIDTH) -
  295.             (int) xv_get(quitbutton, XV_WIDTH) - spacing, NULL);
  296. #undef ip
  297.         button = xv_create(Workman_about->controls3, PANEL_BUTTON,
  298.             PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  299.             window1_button3_notify_callback, NULL);
  300.         xv_set(Workman_about->about, XV_HEIGHT,
  301.             (int) xv_get(button, XV_HEIGHT) + 5 +
  302.             (int) xv_get(Workman_about->about, XV_HEIGHT),
  303.             NULL);
  304.         xv_set(button, XV_X, ((int) xv_get(Workman_about->about,
  305.             XV_WIDTH) - (int) xv_get(button, XV_WIDTH)) / 2,
  306.             XV_Y, (int) xv_get(Workman_about->drive, XV_Y) +
  307.             (int) xv_get(Workman_about->drive, XV_HEIGHT) + 5,
  308.             NULL);
  309.         button = xv_create(Workman_goodies->controls4, PANEL_BUTTON,
  310.             PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  311.             window1_button4_notify_callback, NULL);
  312.         xv_set(Workman_goodies->goodies, XV_HEIGHT,
  313.             (int) xv_get(button, XV_HEIGHT) +
  314.             (int) xv_get(Workman_goodies->goodies, XV_HEIGHT),
  315.             NULL);
  316.         xv_set(button, XV_X, ((int) xv_get(Workman_goodies->goodies,
  317.             XV_WIDTH) - (int) xv_get(button, XV_WIDTH)) / 2,
  318.             XV_Y, (int) xv_get(Workman_goodies->indexscan, XV_Y) +
  319.             (int) xv_get(Workman_goodies->indexscan, XV_HEIGHT) + 5,
  320.             NULL);
  321.     }
  322.  
  323.     srand(getpid());
  324.     xv_set(Workman_window1->songpos, PANEL_INACTIVE, FALSE, NULL);
  325.     kill_stats(Workman_window1);
  326.     track_rect = (Rect *)xv_get(Workman_window1->tracks, PANEL_ITEM_RECT);
  327.  
  328.     xv_set(Workman_goodies->abrepeat, PANEL_INACTIVE, TRUE, NULL);
  329.  
  330.     /* Initialize some stuff Guide won't do. */
  331.     xv_set(Workman_popup1->defaultvolume, PANEL_NOTIFY_LEVEL, PANEL_ALL,
  332.         NULL);
  333.     xv_set(Workman_window1->songpos, PANEL_NOTIFY_LEVEL, PANEL_ALL,
  334.         PANEL_JUMP_DELTA, 5, NULL);
  335.     xv_set(Workman_about->about, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  336.     xv_set(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  337.     xv_set(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  338.     xv_set(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN, FALSE,
  339.         XV_KEY_DATA, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  340.     xv_set(Workman_popup1->whichvolume, PANEL_DEFAULT_VALUE, 1, NULL);
  341.     text_event_handler = (void (*)())xv_get(Workman_popup1->artist,
  342.         PANEL_EVENT_PROC);
  343.     xv_set(Workman_popup1->cdname, PANEL_EVENT_PROC, text_event_p, NULL);
  344.     xv_set(Workman_popup1->artist, PANEL_EVENT_PROC, text_event_p, NULL);
  345.     xv_set(Workman_popup1->trackname, PANEL_EVENT_PROC, text_event_p, NULL);
  346.     small_height = track_rect->r_height;
  347.     next_stopmode(Workman_window1->repeat, cur_stopmode, NULL);
  348.     setup_itimer(Workman_window1, 5);
  349.  
  350.     /*
  351.      * Attempt to lay out the popups somewhat decently.  About goes at
  352.      * the upper left, goodies to its right.
  353.      * CD Info is positioned the first time it appears.
  354.      */
  355.     xv_set(Workman_goodies->goodies, XV_X,
  356.         c = ((int) xv_get(Workman_about->about, XV_WIDTH) + 15), NULL);
  357.     xv_set(Workman_plpopup->plpopup, XV_X,
  358.         (int) xv_get(Workman_goodies->goodies, XV_WIDTH) + c + 15,
  359.         NULL);
  360.  
  361.     window_is_open = ! xv_get(Workman_window1->window1, FRAME_CLOSED);
  362.     notify_interpose_event_func(Workman_window1->window1, check_open,
  363.         NOTIFY_SAFE);
  364.     notify_interpose_destroy_func(Workman_window1->window1, byebye);
  365.     notify_set_signal_func(Workman_window1->window1, sigusr1, SIGUSR1,
  366.         NOTIFY_SYNC);
  367.     notify_set_signal_func(Workman_window1->window1, sigusr2, SIGUSR2,
  368.         NOTIFY_SYNC);
  369.     notify_set_signal_func(Workman_window1->window1, sigquit, SIGQUIT,
  370.         NOTIFY_SYNC);
  371.     notify_set_signal_func(Workman_window1->window1, sigttin, SIGTTIN,
  372.         NOTIFY_SYNC);
  373.     notify_set_signal_func(Workman_window1->window1, sigttou, SIGTTOU,
  374.         NOTIFY_SYNC);
  375.     notify_set_signal_func(Workman_window1->window1, sigemt, SIGEMT,
  376.         NOTIFY_SYNC);
  377.  
  378.     wannasave = xv_create(Workman_window1->window1, NOTICE,
  379.         NOTICE_MESSAGE_STRINGS, "WorkMan alert!", "",
  380.         "You have changed this CD's information,",
  381.         "but you didn't save your changes.", NULL, NOTICE_BUTTON_YES,
  382.         "Save changes", NOTICE_BUTTON_NO, "Discard changes",
  383.         NOTICE_STATUS, &confirmsave, NULL);
  384.     mountedfs = xv_create(Workman_window1->window1, NOTICE,
  385.         NOTICE_MESSAGE_STRINGS, "WorkMan alert!", "",
  386.         "This CD contains a mounted filesystem.",
  387.         "Please run 'umount' before ejecting",
  388.         "or nasty things may happen.", NULL, NOTICE_BUTTON,
  389.         "Okay", 0, NULL);
  390.  
  391.     /*
  392.      * Turn control over to XView.
  393.      */
  394.     xv_main_loop(Workman_window1->window1);
  395.  
  396.     unlink(pidfile);
  397.     exit(0);
  398. }
  399.  
  400. static int time_wanted = -1;
  401.  
  402. static unsigned short sink_bits[8][64 * 16] = { {
  403. #include "bitmaps/sink0"
  404. }, {
  405. #include "bitmaps/sink1"
  406. }, {
  407. #include "bitmaps/sink2"
  408. }, {
  409. #include "bitmaps/sink3"
  410. }, {
  411. #include "bitmaps/sink4"
  412. }, {
  413. #include "bitmaps/sink5"
  414. }, {
  415. #include "bitmaps/sink6"
  416. }, {
  417. #include "bitmaps/sink7"
  418. } };
  419.  
  420. /*
  421.  * Timer handler.  This is called twice a second and updates the clocks and
  422.  * gauges and such.
  423.  */
  424. Notify_value
  425. handle_timer(c, w)
  426. Notify_client    c;
  427. int        w;
  428. {
  429.     window1_objects    *ip = Workman_window1;
  430.     static int    new_image = 0, initted_volume = 0;
  431.     static enum    cd_modes old_cdmode;
  432.     Xv_opaque    old_image;
  433.  
  434.     if (xv_get(ip->mode, PANEL_VALUE) != 5 || ! dont_retry)
  435.         switch (cd_status()) {
  436.         case 0:        /* No CD in drive */
  437.             cur_cdmode = EJECTED;
  438.             if (old_cdmode != EJECTED)
  439.             {
  440.                 if (!xv_get(ip->tracks, PANEL_INACTIVE))
  441.                 {
  442.                     keep_settings(ip);
  443.                     kill_stats(ip);
  444.                     wipe_cdinfo();
  445.                 }
  446.                 xv_set(ip->mode, PANEL_VALUE, 5, NULL);
  447.             }
  448.             break;
  449.         case 1:        /* CD in drive, what state is it in? */
  450.             if (update_everything(ip))
  451.                 return (handle_timer(c, w));
  452.  
  453.             if (cur_cdmode != STOPPED && cur_cdmode != PAUSED ||
  454.                         old_cdmode != cur_cdmode)
  455.                 show_stats(ip);
  456.  
  457.             break;
  458.  
  459.         case 2:        /* CD has just been inserted. */
  460.             new_cd_inserted(ip);
  461.             break;
  462.         }
  463.  
  464.     old_cdmode = cur_cdmode;
  465.  
  466.     if (window_is_open && xv_get(Workman_about->about, XV_SHOW))
  467.     {
  468.         old_image = xv_get(Workman_about->sink, PANEL_LABEL_IMAGE);
  469.         xv_set(Workman_about->sink, PANEL_LABEL_IMAGE,
  470.             xv_create(XV_NULL, SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1,
  471.                 XV_WIDTH, 64, XV_HEIGHT, 64, SERVER_IMAGE_BITS,
  472.                 sink_bits[new_image], NULL), NULL);
  473.         xv_destroy(old_image);
  474.         new_image = (new_image + 1) & 7;
  475.     }
  476.  
  477.     return (NOTIFY_DONE);
  478. }
  479.  
  480. /*
  481.  * The CD is in the drive.  Update all the necessary screen elements and handle
  482.  * end-of-track and so forth.  Returns 1 if handle_timer() should get the CD
  483.  * status again immediately because of unusual conditions such as the user
  484.  * fiddling with the track-position slider.
  485.  */
  486. update_everything(ip)
  487.     window1_objects *ip;
  488. {
  489.     if (cur_cdmode == TRACK_DONE)        /* Done with track... */
  490.     {
  491. donewithcd:
  492.         if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE))
  493.         {
  494.             play_chunk(mark_a, mark_b);
  495.             return (1);
  496.         }
  497.         if (was_repeating)
  498.         {
  499.             was_repeating = 0;
  500.             play_chunk(mark_b, cur_lasttrack >= cur_ntracks ?
  501.                 (cd->length - 1) * 75 :
  502.                 cd->trk[cur_lasttrack].start-1);
  503.             return (1);
  504.         }
  505.  
  506.         play_next_entry();
  507.         if (cd_status() != 1)
  508.             return (1);
  509.         if (cur_cdmode == STOPPED)    /* Done with CD */
  510.         {
  511.             xv_set(Workman_goodies->abrepeat,
  512.                 PANEL_VALUE, FALSE, NULL);
  513.             switch (xv_get(ip->repeat, PANEL_VALUE))
  514.             {
  515.             case 1:
  516.                 make_playlist(xv_get(ip->shuffle,
  517.                     PANEL_VALUE), 0);
  518.                 play_next_entry();
  519.                 break;
  520.             case 2:
  521.                 keep_settings(ip);
  522.                 if (info_modified)
  523.                 {
  524.                     xv_set(wannasave, XV_SHOW, TRUE, NULL);
  525.                     if (confirmsave)
  526.                         save_config(NULL, NULL);
  527.                     info_modified = 0;
  528.                 }
  529.                 if (eject_cd() == 0)
  530.                 {
  531.                     setup_itimer(ip, 5);
  532.                     kill_stats(ip);
  533.                 }
  534.                 break;
  535.             default:
  536.                 icon_label("Stop");
  537.                 xv_set(ip->tracks, PANEL_VALUE, -1, NULL);
  538.                 xv_set(ip->tracklen, PANEL_LABEL_STRING,
  539.                     "0:00", NULL);
  540.                 cur_pos_abs = cur_pos_rel = 0;
  541.                 cur_tracklen = 0;
  542.                 new_trackname_display("", 0);
  543.                 xv_set(Workman_goodies->delete,
  544.                     PANEL_INACTIVE, TRUE, NULL);
  545.                 xv_set(Workman_goodies->split,
  546.                     PANEL_INACTIVE, TRUE, NULL);
  547.                 reset_cdlen(ip);
  548.                 displayed_track = -1;
  549.                 cur_track = -1;
  550.             }
  551.         }
  552.     }
  553.  
  554.     /* We're at the end of the previous track. */
  555.     if (cur_firsttrack != -1 && cur_track < cur_firsttrack)
  556.         cur_track = cur_firsttrack;
  557.  
  558.     /* The slider has been moved... */
  559.     if (time_wanted > -1 && cur_cdmode == PLAYING)
  560.     {
  561.         play_from_pos(time_wanted);
  562.         time_wanted = -2;
  563.         return (1);
  564.     }
  565.     if (time_wanted == -2)
  566.     {
  567.         time_wanted = -1;
  568.         xv_set(ip->cdgauge, PANEL_VALUE, cur_pos_abs, NULL);
  569.     }
  570.  
  571.     /* We've hit the start of a track we don't want. */
  572.     if (cur_lasttrack != -1 && cur_track > cur_lasttrack)
  573.         goto donewithcd;
  574.  
  575.     return (0);
  576. }
  577.  
  578. Defaults_pairs autoplay_modes[] = {
  579.     "never",    0,
  580.     "normal",    1,
  581.     "always",    2,
  582.     NULL,        1
  583. };
  584.  
  585. /*
  586.  * A new CD has just been inserted, or possibly we're just starting up and
  587.  * there was already a CD in the drive.  Make all the necessary preparations.
  588.  * Called from handle_timer().
  589.  */
  590. void
  591. new_cd_inserted(ip)
  592.     window1_objects    *ip;
  593. {
  594.     static int    initted_volume = 0;
  595.     static int    autoplay = -1;
  596.     int        volume, max;
  597.  
  598.     if (! initted_volume)
  599.     {
  600.         initted_volume = 1;
  601.  
  602.         /*
  603.          * The function is being called for the first time.
  604.          *
  605.          * Set the volume to the resource-specified initial volume.
  606.          * If that's not available try to read the current volume from
  607.          * the hardware and set the slider accordingly.
  608.          */
  609.         volume = defaults_get_integer("workman.initialVolume",
  610.                 "Workman.InitialVolume",
  611.                 read_initial_volume(100));
  612.         if (volume < 0)
  613.             volume = 0;
  614.         if (volume > 100)
  615.             volume = 100;
  616.         /*
  617.          * Scale the value to the resolution of the volume knob.
  618.          */
  619.         max = xv_get(ip->volume, PANEL_MAX_VALUE);
  620.         volume = (volume * max) / 100;
  621.  
  622.         xv_set(ip->volume, PANEL_VALUE, volume,
  623.             PANEL_NOTIFY_LEVEL, PANEL_ALL, NULL);
  624.         xv_set(Workman_goodies->balance, PANEL_NOTIFY_LEVEL, PANEL_ALL,
  625.             PANEL_VALUE, cur_balance, NULL);
  626.         cd_volume(volume, cur_balance, max);
  627.     }
  628.  
  629.     info_modified = 0;
  630.     if (dont_retry > 1)
  631.         dont_retry = 0;
  632.     setup_itimer(ip, 0);
  633.     init_stats(ip);
  634.     xv_set(ip->repeat, PANEL_VALUE, cur_stopmode, NULL);
  635.     xv_set(Workman_goodies->playnewcds, PANEL_VALUE, cur_playnew, NULL);
  636.     show_stats(ip);
  637.     cd_status();
  638.  
  639.     /* See if the user has specified an insertion policy in his resources.*/
  640.     autoplay = defaults_get_enum("workman.autoPlay",
  641.                 "Workman.AutoPlay", autoplay_modes);
  642.  
  643.     if (autoplay == 2 || (autoplay == 1 && ((cur_playnew && !found_in_rc) ||
  644.                 get_autoplay())) || cur_cdmode == PLAYING)
  645.         make_initial_playlist(get_playmode());
  646. }
  647.  
  648. /*
  649.  * Make an initial playlist.  If the CD was already playing, skip forward in
  650.  * the list to an entry where the current track would be playing (except in
  651.  * Shuffle mode; in that case, start a new random list beginning with
  652.  * the current track.)
  653.  */
  654. void
  655. make_initial_playlist(playmode)
  656.     int    playmode;
  657. {
  658.     if (cur_cdmode == PLAYING)
  659.     {
  660.         if (playmode == 1)
  661.         {
  662.             make_playlist(1, cur_track);
  663.             cur_listno = 1;
  664.         }
  665.         else
  666.         {
  667.             make_playlist(playmode, 0);
  668.             pl_find_track(cur_track);
  669.         }
  670.     }
  671.     else
  672.     {
  673.         make_playlist(get_playmode(), 0);
  674.         play_next_entry();
  675.     }
  676. }
  677.  
  678. /*
  679.  * Set up the interval timers.
  680.  */
  681. void
  682. setup_itimer(ip, interval)
  683.     window1_objects *ip;
  684.     int        interval;
  685. {
  686.     static struct itimerval it;
  687.  
  688.     it.it_value.tv_sec = 0;
  689.     it.it_value.tv_usec = 500000;
  690.     it.it_interval.tv_sec = interval;
  691.     it.it_interval.tv_usec = interval ? 0 : 500000;
  692.     notify_set_itimer_func(ip->window1, handle_timer, ITIMER_REAL,
  693.         &it, NULL);
  694. }
  695.  
  696. /*
  697.  * Notify callback function for `mode'.
  698.  */
  699. void
  700. change_mode(item, value, event)
  701.     Panel_item    item;
  702.     int        value;
  703.     Event        *event;
  704. {
  705.     window1_objects *ip = Workman_window1;
  706.     int    track, playmode;
  707.  
  708.     if (cur_cdmode == EJECTED && dont_retry)
  709.         handle_timer(NULL, NULL);
  710.     if (cur_cdmode == EJECTED || (cur_track == -1 && (value == 0 || value == 2)))
  711.     {
  712.         xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL);
  713.         return;
  714.     }
  715.  
  716.     switch (value) {
  717.     case 0:        /* back a track */
  718.         if (cur_cdmode == PLAYING)
  719.         {
  720.             play_prev_track();
  721.             cd_status();
  722.         }
  723.         else if (cur_track > 1)
  724.         {
  725.             cur_track--;
  726.             time_wanted = 0;
  727.             cur_pos_rel = time_wanted;
  728.             cur_frame = cd->trk[cur_track - 1].start +
  729.                 time_wanted * 75;
  730.             cur_pos_abs = cur_frame / 75;
  731.         }
  732.  
  733.         if (cur_cdmode == PLAYING || cur_cdmode == STOPPED)
  734.             xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL);
  735.  
  736.         if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE))
  737.             xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE,
  738.                 NULL);
  739.         displayed_track = -1;
  740.         if (cur_track < cur_firsttrack)
  741.             cur_track = cur_firsttrack;
  742.         show_stats(ip);
  743.         break;
  744.  
  745.     case 1:        /* play */
  746.         if (cur_cdmode == PAUSED)
  747.         {
  748.             pause_cd();
  749.             show_stats(ip);
  750.             break;
  751.         }
  752.         if (cur_cdmode == STOPPED)
  753.         {
  754.             /* XXX should call make_initial_playlist() */
  755.             track = xv_get(ip->tracks, PANEL_VALUE) + 1;
  756.             playmode = xv_get(ip->shuffle, PANEL_VALUE);
  757.             if (playmode == 1)
  758.                 make_playlist(1, track);
  759.             else
  760.             {
  761.                 make_playlist(playmode, 0);
  762.                 if (track)
  763.                 {
  764.                     pl_find_track(track);
  765.                     cur_track = track;
  766.                     cur_cdmode = PLAYING;
  767.                     play_from_pos(0);
  768.                     displayed_track = -1;
  769.                 }
  770.             }
  771.         }
  772.         if (cur_cdmode != PLAYING)
  773.             play_next_entry();
  774.         cd_status();
  775.  
  776.         /* We're at the end of the previous track. */
  777.         if (cur_track < cur_firsttrack)
  778.             cur_track = cur_firsttrack;
  779.  
  780.         if (displayed_track == -1)
  781.             new_track(ip);
  782.         break;
  783.  
  784.     case 2:        /* forward a track */
  785.         if (cur_cdmode == PLAYING)
  786.         {
  787.             play_next_track();
  788.             if (cur_cdmode == STOPPED)
  789.                 goto stopped;
  790.             cd_status();
  791.         }
  792.         else if (cur_track < cur_ntracks)
  793.         {
  794.             cur_track++;
  795.             time_wanted = 0;
  796.             cur_pos_rel = time_wanted;
  797.             cur_frame = cd->trk[cur_track - 1].start +
  798.                 time_wanted * 75;
  799.             cur_pos_abs = cur_frame / 75;
  800.         }
  801.  
  802.         if (cur_cdmode == PLAYING || cur_cdmode == STOPPED)
  803.             xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL);
  804.  
  805.         if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE))
  806.             xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE,
  807.                 NULL);
  808.         if (cur_track < cur_firsttrack)
  809.             cur_track = cur_firsttrack;
  810.         show_stats(ip);
  811.         break;
  812.  
  813.     case 3:        /* pause */
  814.         pause_cd();
  815.         show_stats(ip);
  816.         break;
  817.     case 4:        /* stop */
  818.         stop_cd();
  819.         cd_status();
  820. stopped:
  821.         cur_pos_abs = cur_pos_rel = 0;
  822.         cur_tracklen = 0;
  823.         new_trackname_display("", 0);
  824.         reset_cdlen(ip);
  825.         icon_label("Stop");
  826.         xv_set(ip->tracks, PANEL_VALUE, -1, NULL);
  827.         xv_set(ip->tracklen, PANEL_LABEL_STRING, "0:00", NULL);
  828.         xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE, NULL);
  829.         xv_set(Workman_goodies->split, PANEL_INACTIVE, TRUE, NULL);
  830.         xv_set(Workman_goodies->delete, PANEL_INACTIVE, TRUE, NULL);
  831.         displayed_track = -1;
  832.         cur_track = -1;
  833.         break;
  834.     case 5:        /* eject */
  835.         keep_settings(ip);
  836.  
  837.         if (info_modified)
  838.         {
  839.             xv_set(wannasave, XV_SHOW, TRUE, NULL);
  840.             if (confirmsave)
  841.                 save_config(NULL, NULL);
  842.             info_modified = 0;
  843.         }
  844.  
  845.         switch (eject_cd()) {
  846.         case 0:
  847.             setup_itimer(ip, 5);
  848.             kill_stats(ip);
  849.             /*
  850.              * need to call wipe_cdinfo() because the one in
  851.              * handle_timer() won't be used with -e -e
  852.              */
  853.             wipe_cdinfo();
  854.             break;
  855.         case 1:
  856.             xv_set(ip->mode, PANEL_VALUE, 4, NULL);
  857.             break;    /* XXX - should display an error popup */
  858.         case 2:
  859.             xv_set(ip->mode, PANEL_VALUE, 4, NULL);
  860.             xv_set(mountedfs, XV_SHOW, TRUE, NULL);
  861.             break;
  862.         }
  863.  
  864.         break;
  865.     }
  866. }
  867.  
  868. /*
  869.  * Notify callback function for `button2'.  Show the CD Info popup.
  870.  */
  871. void
  872. window1_button2_notify_callback(item, event)
  873.     Panel_item    item;
  874.     Event        *event;
  875. {
  876.     window1_objects *ip = Workman_window1;
  877.     int        cdi_width, cdi_height, wm_width, wm_x, c;
  878.     static int    positioned = 0;
  879.     Xv_Screen    screen;
  880.     Display        *dpy;
  881.  
  882.     /*
  883.      * CD Info is positioned (badly) at this point.  It goes to the right
  884.      * of the main window if it'll fit, to the left if not, aligned with
  885.      * the top of the main window as closely as possible.  This is not
  886.      * as nice as it could be, but is probably as nice as it's gonna get.
  887.      *
  888.      * XXX We make (BAD BAD BAD) assumptions about the size of the window
  889.      *    decorations so things line up right under olwm.
  890.      */
  891.     if (! positioned)
  892.     {
  893.         positioned = 1;
  894.         dpy = (Display *) xv_get(ip->window1, XV_DISPLAY);
  895.         screen = (Xv_Screen) xv_get(ip->window1, XV_SCREEN);
  896.         c = (int) xv_get(screen, SCREEN_NUMBER);
  897.         cdi_width = (int) xv_get(Workman_popup1->popup1, XV_WIDTH);
  898.         cdi_height = (int) xv_get(Workman_popup1->popup1, XV_HEIGHT);
  899.         wm_width = (int) xv_get(ip->window1, XV_WIDTH);
  900.         wm_x = (int) xv_get(ip->window1, XV_X);
  901.         if (wm_width + cdi_width + 10 + (int) xv_get(ip->window1,
  902.                 XV_X) > DisplayWidth(dpy, c))
  903.             xv_set(Workman_popup1->popup1, XV_X, wm_x - cdi_width -
  904.                 20 < 0 ? 0 : wm_x - cdi_width - 20, NULL);
  905.         else
  906.             xv_set(Workman_popup1->popup1, XV_X, wm_x + wm_width +
  907.                 10, NULL);
  908.         if ((int) xv_get(ip->window1, XV_Y) + cdi_height >
  909.                             DisplayHeight(dpy, c))
  910.             xv_set(Workman_popup1->popup1, XV_Y,
  911.                 DisplayHeight(dpy, c) - cdi_height - 28, NULL);
  912.         else
  913.             xv_set(Workman_popup1->popup1, XV_Y, xv_get(ip->
  914.                 window1, XV_Y) - 25, NULL);
  915.     }
  916.     
  917.     if (dismiss_button && item == ip->button2 ||
  918.         xv_get(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN) == FALSE)
  919.     {
  920.         xv_set(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN, TRUE,
  921.             NULL);
  922.         xv_set(Workman_popup1->popup1, XV_SHOW, TRUE, NULL);
  923.         if (xv_get(Workman_plpopup->plpopup, XV_KEY_DATA,
  924.                             FRAME_CMD_PUSHPIN_IN))
  925.             xv_set(Workman_plpopup->plpopup, XV_SHOW, TRUE,
  926.                 FRAME_CMD_PUSHPIN_IN, TRUE, XV_KEY_DATA,
  927.                 FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  928.     }
  929.     else
  930.     {
  931.         xv_set(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN, FALSE,
  932.             XV_SHOW, FALSE, NULL);
  933.         xv_set(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN, FALSE,
  934.             XV_KEY_DATA, FRAME_CMD_PUSHPIN_IN,
  935.             xv_get(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN),
  936.             XV_SHOW, FALSE, NULL);
  937.     }
  938. }
  939.  
  940. /*
  941.  * Notify callback function for `tracks'.
  942.  */
  943. void
  944. change_track(item, value, event)
  945.     Panel_item    item;
  946.     int        value;
  947.     Event        *event;
  948. {
  949.     window1_objects *ip = Workman_window1;
  950.     
  951.     if (cur_cdlen > 0 && cur_cdmode != EJECTED)
  952.     {
  953.         if (value == -1)
  954.         {
  955.             if (cur_cdmode == PLAYING || cur_cdmode == PAUSED)
  956.                 xv_set(item, PANEL_VALUE, cur_track - 1, NULL);
  957.             else
  958.             {
  959.                 xv_set(Workman_goodies->split, PANEL_INACTIVE,
  960.                     TRUE, NULL);
  961.                 xv_set(Workman_goodies->delete, PANEL_INACTIVE,
  962.                     TRUE, NULL);
  963.                 cur_track = -1;
  964.             }
  965.         }
  966.         else
  967.             cur_track = value + 1;
  968.  
  969.         if (cur_cdmode == PLAYING)
  970.         {
  971.             pl_find_track(cur_track);
  972.             play_from_pos(0);
  973.             cd_status();
  974.             if (cur_track < cur_firsttrack)
  975.                 cur_track = cur_firsttrack;
  976.         }
  977.         new_track(ip);
  978.     }
  979. }
  980.  
  981. /*
  982.  * Notify callback function for `songpos'.
  983.  */
  984. void
  985. change_pos(item, value, event)
  986.     Panel_item    item;
  987.     int        value;
  988.     Event        *event;
  989. {
  990.     char    time[6];
  991.     int    value_left;
  992.     
  993.     time_wanted = value;
  994.  
  995.     if (cur_cdmode == STOPPED && cur_track > 0)
  996.     {
  997.         if (! xv_get(Workman_goodies->timemode_track, PANEL_VALUE))
  998.             sprintf(time, "%02d:%02d", value / 60, value % 60);
  999.         else
  1000.         {
  1001.             value_left = tracklen(cur_track - 1) - value;
  1002.             if (value < 0)
  1003.                 value = 0;
  1004.             sprintf(time, "%02d:%02d", value_left / 60,
  1005.                             value_left % 60);
  1006.         }
  1007.  
  1008.         xv_set(Workman_window1->tracktimer, PANEL_LABEL_STRING, time,
  1009.             NULL);
  1010.         cur_pos_rel = time_wanted;
  1011.         cur_frame = cd->trk[cur_track - 1].start + time_wanted * 75;
  1012.         cur_pos_abs = cur_frame / 75;
  1013.     }
  1014.  
  1015.     if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE))
  1016.         xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE, NULL);
  1017. }
  1018.  
  1019. /*
  1020.  * Notify callback function for `shuffle'.
  1021.  */
  1022. void
  1023. next_playmode_default(item, value, event)
  1024.     Panel_item    item;
  1025.     int        value;
  1026.     Event        *event;
  1027. {
  1028.     int    newdefault;
  1029.     
  1030.     if (value == 0)
  1031.         newdefault = 1;
  1032.     else
  1033.         if (cd->lists == NULL || cd->lists[value - 1].name == NULL)
  1034.             newdefault = 0;
  1035.         else
  1036.             newdefault = value + 1;
  1037.  
  1038.     xv_set(item, PANEL_DEFAULT_VALUE, newdefault, NULL);
  1039. }
  1040.  
  1041. /*
  1042.  * Notify callback function for `playlist'.
  1043.  */
  1044. int
  1045. playlist_notify(item, string, client_data, op, event, row)
  1046.     Panel_item    item;
  1047.     char        *string;
  1048.     Xv_opaque    client_data;
  1049.     Panel_list_op    op;
  1050.     Event        *event;
  1051.     int        row;
  1052. {
  1053.     plpopup_objects *ip = Workman_plpopup;
  1054.     
  1055.     switch(op) {
  1056.     case PANEL_LIST_OP_DESELECT:
  1057.         pl_item = -1;
  1058.         xv_set(ip->delete, PANEL_INACTIVE, TRUE, NULL);
  1059.         break;
  1060.  
  1061.     case PANEL_LIST_OP_SELECT:
  1062.         pl_item = row;
  1063.         xv_set(ip->delete, PANEL_INACTIVE, FALSE, NULL);
  1064.         break;
  1065.  
  1066.     case PANEL_LIST_OP_VALIDATE:
  1067.     case PANEL_LIST_OP_DELETE:
  1068.         break;
  1069.     }
  1070.     return XV_OK;
  1071. }
  1072.  
  1073. unsigned short speaker_bits[8][15] = { {
  1074. #include "bitmaps/loud0.icon"
  1075. }, {
  1076. #include "bitmaps/loud1.icon"
  1077. }, {
  1078. #include "bitmaps/loud2.icon"
  1079. }, {
  1080. #include "bitmaps/loud3.icon"
  1081. }, {
  1082. #include "bitmaps/loud4.icon"
  1083. }, {
  1084. #include "bitmaps/loud5.icon"
  1085. }, {
  1086. #include "bitmaps/loud6.icon"
  1087. }, {
  1088. #include "bitmaps/loud.icon"
  1089. } };
  1090.  
  1091. /*
  1092.  * Notify callback function for `volume'.
  1093.  */
  1094. void
  1095. set_volume(item, value, event)
  1096.     Panel_item    item;
  1097.     int        value;
  1098.     Event        *event;
  1099. {
  1100.     window1_objects *ip = Workman_window1;
  1101.     static int    old_image = 7;
  1102.     Xv_opaque    old_serverimage;
  1103.     int        max = xv_get(item, PANEL_MAX_VALUE);
  1104.     int        new_image;
  1105.  
  1106.     manual_volume = 1;
  1107.  
  1108.     cd_volume(value, cur_balance, max);
  1109.  
  1110.     /* maybe show a new icon... */
  1111.     new_image = value / (max / 8);
  1112.  
  1113.     if (new_image > 7)
  1114.         new_image = 7;
  1115.     if (new_image != old_image)
  1116.     {
  1117.         old_serverimage = xv_get(ip->speaker, PANEL_LABEL_IMAGE);
  1118.         xv_set(ip->speaker, PANEL_LABEL_IMAGE, xv_create(XV_NULL,
  1119.             SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1, XV_WIDTH, 16,
  1120.             XV_HEIGHT, 15, SERVER_IMAGE_BITS,
  1121.             speaker_bits[new_image], NULL), NULL);
  1122.         xv_destroy(old_serverimage);
  1123.         old_image = new_image;
  1124.     }
  1125. }
  1126.  
  1127. /*
  1128.  * Figure out the proper volume for this track and set it.  If the user has
  1129.  * touched the manual volume knob, use that setting instead of any default.
  1130.  *
  1131.  * XXX defaults should still affect the volume depending on how much the
  1132.  * user changed it manually.
  1133.  */
  1134. void
  1135. figure_volume(ip)
  1136.     window1_objects *ip;
  1137. {
  1138.     int volume = 0, old_manual = manual_volume;
  1139.  
  1140.     if (! manual_volume)
  1141.     {
  1142.         if (cur_track)
  1143.             volume = get_default_volume(cur_track);
  1144.         if (! volume)
  1145.             volume = get_default_volume(0);
  1146.     }
  1147.     if (! volume)
  1148.         volume = xv_get(ip->volume, PANEL_VALUE);
  1149.     xv_set(ip->volume, PANEL_VALUE, volume, NULL);
  1150.     set_volume(ip->volume, volume, NULL);
  1151.     manual_volume = old_manual;
  1152. }
  1153.  
  1154. /*
  1155.  * Notify callback function for `button3'.
  1156.  */
  1157. void
  1158. window1_button3_notify_callback(item, event)
  1159.     Panel_item    item;
  1160.     Event        *event;
  1161. {
  1162.     window1_objects *ip = Workman_window1;
  1163.     
  1164.     if (dismiss_button && item == ip->button3 ||
  1165.         xv_get(Workman_about->about, FRAME_CMD_PUSHPIN_IN) == FALSE)
  1166.     {
  1167.         xv_set(Workman_about->about, FRAME_CMD_PUSHPIN_IN, TRUE, NULL);
  1168.         xv_set(Workman_about->about, XV_SHOW, TRUE, NULL);
  1169.     }
  1170.     else
  1171.         xv_set(Workman_about->about, FRAME_CMD_PUSHPIN_IN, FALSE,
  1172.             XV_SHOW, FALSE, NULL);
  1173. }
  1174.  
  1175. /*
  1176.  * Notify callback function for `button4'.
  1177.  */
  1178. void
  1179. window1_button4_notify_callback(item, event)
  1180.     Panel_item    item;
  1181.     Event        *event;
  1182. {
  1183.     window1_objects *ip = Workman_window1;
  1184.     
  1185.     if (dismiss_button && item == ip->button4 ||
  1186.         xv_get(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN) == FALSE)
  1187.     {
  1188.         xv_set(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN, TRUE,
  1189.             NULL);
  1190.         xv_set(Workman_goodies->goodies, XV_SHOW, TRUE, NULL);
  1191.     }
  1192.     else
  1193.         xv_set(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN, FALSE,
  1194.             XV_SHOW, FALSE, NULL);
  1195. }
  1196.  
  1197. static unsigned short phone_bits[7][22] = { {
  1198. #include "bitmaps/phonesl3"
  1199. }, {
  1200. #include "bitmaps/phonesl2"
  1201. }, {
  1202. #include "bitmaps/phonesl1"
  1203. }, {
  1204. #include "bitmaps/phones0"
  1205. }, {
  1206. #include "bitmaps/phonesr1"
  1207. }, {
  1208. #include "bitmaps/phonesr2"
  1209. }, {
  1210. #include "bitmaps/phonesr3"
  1211. } };
  1212.  
  1213. /*
  1214.  * Notify callback function for `balance'.
  1215.  */
  1216. void
  1217. slide_balance(item, value, event)
  1218.     Panel_item    item;
  1219.     int        value;
  1220.     Event        *event;
  1221. {
  1222.     goodies_objects *ip = Workman_goodies;
  1223.     static int    old_image = 3;
  1224.     Xv_opaque    old_serverimage;
  1225.     int        max = xv_get(item, PANEL_MAX_VALUE);
  1226.     int        new_image;
  1227.  
  1228.     new_image = value / (max / 6);
  1229.  
  1230.     /* maybe show a new icon... */
  1231.     if (new_image > 6)
  1232.         new_image = 6;
  1233.     if (new_image != old_image)
  1234.     {
  1235.         old_serverimage = xv_get(ip->phones, PANEL_LABEL_IMAGE);
  1236.         xv_set(ip->phones, PANEL_LABEL_IMAGE, xv_create(XV_NULL,
  1237.             SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1, XV_WIDTH, 16,
  1238.             XV_HEIGHT, 22, SERVER_IMAGE_BITS,
  1239.             phone_bits[new_image], NULL), NULL);
  1240.         xv_destroy(old_serverimage);
  1241.         old_image = new_image;
  1242.     }
  1243.  
  1244.     cur_balance = value;
  1245.     figure_volume(Workman_window1);
  1246. }
  1247.  
  1248. /*
  1249.  * Notify callback function for `repeat'.
  1250.  * Change the current stopmode; then select a new default value for the
  1251.  * choice item.  Wrap around when we hit the end of the playlists.
  1252.  */
  1253. void
  1254. next_stopmode(item, value, event)
  1255.     Panel_item    item;
  1256.     int        value;
  1257.     Event        *event;
  1258. {
  1259.     cur_stopmode = value;
  1260.     xv_set(item, PANEL_DEFAULT_VALUE, (value + 1) % 3, NULL);
  1261. }
  1262.  
  1263. /*
  1264.  * Notify callback function for `abrepeat'.
  1265.  */
  1266. void
  1267. goodies_abrepeat_notify_callback(item, value, event)
  1268.     Panel_item    item;
  1269.     int        value;
  1270.     Event        *event;
  1271. {
  1272.     if (value & 1)
  1273.         start_repeating(item, value, event);
  1274.     else
  1275.         stop_repeating(item, value, event);
  1276. }
  1277.  
  1278. /*
  1279.  * User-defined action for `abrepeat'.
  1280.  */
  1281. void
  1282. start_repeating(item, value, event)
  1283.     Panel_item    item;
  1284.     int        value;
  1285.     Event        *event;
  1286. {
  1287.     cur_firsttrack = cur_lasttrack = -1;
  1288.     play_chunk(mark_a, mark_b);
  1289. }
  1290.  
  1291. /*
  1292.  * Set one of the A-B repeat time messages.  "which" should be 0 for the A
  1293.  * timer and 1 for the B timer.
  1294.  */
  1295. void
  1296. set_abtimer(which, frame)
  1297.     int        which;
  1298.     int        frame;
  1299. {
  1300.     char    buf[30];
  1301.     int    tnum, relpos;
  1302.  
  1303.     if (frame < cd->trk[0].start || frame > cd->length * 75)
  1304.         return;
  1305.  
  1306.     for (tnum = 1; tnum < cur_ntracks; tnum++)
  1307.         if (frame < cd->trk[tnum].start)
  1308.             break;
  1309.     tnum--;
  1310.     relpos = (frame - cd->trk[tnum].start) / 75;
  1311.  
  1312.     if (cd->trk[tnum].section)
  1313.         sprintf(buf, "Track: %02d.%02d Time: %02d:%02d",
  1314.             cd->trk[tnum].track, cd->trk[tnum].section,
  1315.             relpos / 60, relpos % 60);
  1316.     else
  1317.         sprintf(buf, "Track: %02d      Time: %02d:%02d",
  1318.             cd->trk[tnum].track, relpos / 60, relpos % 60);
  1319.  
  1320.     if (which)
  1321.     {
  1322.         if (mark_a && frame <= mark_a)
  1323.             return;
  1324.  
  1325.         mark_b = frame;
  1326.         xv_set(Workman_goodies->blabel, PANEL_LABEL_STRING, buf, NULL);
  1327.     }
  1328.     else
  1329.     {
  1330.         if (mark_b && frame >= mark_b)
  1331.         {
  1332.             mark_b = 0;
  1333.             return;
  1334.         }
  1335.  
  1336.         mark_a = frame;
  1337.         xv_set(Workman_goodies->alabel, PANEL_INACTIVE, FALSE,
  1338.             PANEL_LABEL_STRING, buf, NULL);
  1339.     }
  1340.  
  1341.     if (mark_a && mark_b && mark_a < mark_b)
  1342.     {
  1343.         xv_set(Workman_goodies->abrepeat, PANEL_INACTIVE, FALSE, NULL);
  1344.         xv_set(Workman_goodies->blabel, PANEL_INACTIVE, FALSE, NULL);
  1345.     }
  1346. }
  1347.  
  1348. /*
  1349.  * Notify callback function for `a'.
  1350.  */
  1351. void
  1352. section_start(item, event)
  1353.     Panel_item    item;
  1354.     Event        *event;
  1355. {
  1356.     goodies_objects *ip = Workman_goodies;
  1357.     
  1358.     set_abtimer(0, cur_frame);
  1359.     xv_set(ip->blabel, PANEL_INACTIVE, TRUE, NULL);
  1360.     mark_b = 0;
  1361.     xv_set(ip->abrepeat, PANEL_VALUE, FALSE, PANEL_INACTIVE, TRUE, NULL);
  1362. }
  1363.  
  1364. /*
  1365.  * Notify callback function for `b'.
  1366.  */
  1367. void
  1368. section_end(item, event)
  1369.     Panel_item    item;
  1370.     Event        *event;
  1371. {
  1372.     set_abtimer(1, cur_frame);
  1373. }
  1374.  
  1375. /*
  1376.  * Notify callback function for `button6'.
  1377.  */
  1378. void
  1379. rename_playlist(item, event)
  1380.     Panel_item    item;
  1381.     Event        *event;
  1382. {
  1383.     plpopup_objects *ip = Workman_plpopup;
  1384.     char    *name = (char *) xv_get(ip->listname, PANEL_VALUE);
  1385.     int    i;
  1386.  
  1387.     info_modified = 1;
  1388.  
  1389.     if (name[0] == '\0' || pl_listnum == -1)
  1390.         return;
  1391.  
  1392.     for (i = 0; cd->lists[i].name != NULL; i++)
  1393.         if (i != pl_listnum && ! strcmp(name, cd->lists[i].name))
  1394.             break;
  1395.  
  1396.     if (cd->lists[i].name != NULL)
  1397.     {
  1398.         notice_prompt(ip->plpopup, event, NOTICE_FOCUS_XY,
  1399.             event_x(event), event_y(event), NOTICE_MESSAGE_STRINGS,
  1400.             "The name", name, "is already being used",
  1401.             NULL, NOTICE_BUTTON, "Comprendo", 101, NULL);
  1402.         return;
  1403.     }
  1404.  
  1405.     strmcpy(&cd->lists[pl_listnum].name, name);
  1406.     xv_set(ip->playlists, PANEL_LIST_STRING, pl_listnum, name, NULL);
  1407.     xv_set(Workman_window1->shuffle, PANEL_CHOICE_STRING, pl_listnum + 2,
  1408.         name, NULL);
  1409. }
  1410.  
  1411. /*
  1412.  * User-defined action for `button7'.
  1413.  * Add a new playlist to the system.  If the user has specified a name, use
  1414.  * it; otherwise make up a lettered name ("List X") based on the list's
  1415.  * position in the list of lists.
  1416.  */
  1417. void
  1418. add_playlist(item, event)
  1419.     Panel_item    item;
  1420.     Event        *event;
  1421. {
  1422.     plpopup_objects *ip = Workman_plpopup;
  1423.     char    *name = (char *) xv_get(ip->listname, PANEL_VALUE);
  1424.     char    fakename[sizeof("List XXX")];
  1425.     int    i;
  1426.     char    c;
  1427.  
  1428.     info_modified = 1;
  1429.  
  1430.     if (name[0] == '\0')
  1431.     {
  1432.         name = fakename;
  1433.         strcpy(name, "List A");
  1434.         if (cd->lists != NULL && cd->lists[0].name != NULL)
  1435.             for (c = 'A'; c < 'z'; c++)
  1436.             {
  1437.                 name[sizeof("List")] = c;
  1438.                 for (i = 0; cd->lists[i].name != NULL; i++)
  1439.                     if (! strcmp(name, cd->lists[i].name))
  1440.                         break;
  1441.                 if (! cd->lists[i].name)
  1442.                     break;
  1443.                 if (c == 'Z')
  1444.                     c = 'a' - 1;
  1445.             }
  1446.     }
  1447.     else if (cd->lists != NULL)
  1448.         for (i = 0; cd->lists[i].name != NULL; i++)
  1449.             if (! strcmp(name, cd->lists[i].name))
  1450.                 break;
  1451.  
  1452.     if (cd->lists != NULL && cd->lists[i].name != NULL)
  1453.     {
  1454.         notice_prompt(ip->plpopup, event, NOTICE_FOCUS_XY,
  1455.             event_x(event), event_y(event), NOTICE_MESSAGE_STRINGS,
  1456.             "The name", name, "is already being used",
  1457.             NULL, NOTICE_BUTTON, "Comprendo", 101, NULL);
  1458.         return;
  1459.     }
  1460.  
  1461.     /* Make the list itself internally. */
  1462.     if (new_list(cd, name) == NULL)
  1463.     {
  1464.         perror("new_list");
  1465.         exit(1);
  1466.     }
  1467.  
  1468.     /* Add the list to the scrolling list of playlists. */
  1469.     i = (int) xv_get(ip->playlists, PANEL_LIST_NROWS);
  1470.     xv_set(ip->playlists, PANEL_LIST_INSERT, i, PANEL_LIST_STRING,
  1471.         i, name, PANEL_LIST_SELECT, i, TRUE, NULL);
  1472.     switch_playlists(ip->playlists, NULL, NULL, PANEL_LIST_OP_SELECT,
  1473.         NULL, i);
  1474.  
  1475.     /* ...And to the play mode choice item on the main window. */
  1476.     xv_set(Workman_window1->shuffle, PANEL_CHOICE_STRING, i + 2, name,
  1477.         NULL);
  1478.     if (xv_get(Workman_window1->shuffle, PANEL_DEFAULT_VALUE) == 0)
  1479.         xv_set(Workman_window1->shuffle, PANEL_DEFAULT_VALUE, i + 2,
  1480.             NULL);
  1481. }
  1482.  
  1483. /*
  1484.  * Notify callback function for `button5'.
  1485.  */
  1486. void
  1487. delete_playlist(item, event)
  1488.     Panel_item    item;
  1489.     Event        *event;
  1490. {
  1491.     plpopup_objects *ip = Workman_plpopup;
  1492.     int    nlists = xv_get(ip->playlists, PANEL_LIST_NROWS);
  1493.     int    shuf, i;
  1494.     
  1495.     info_modified = 1;
  1496.  
  1497.     if (pl_listnum >= 0)
  1498.     {
  1499.         xv_set(ip->playlists, PANEL_LIST_DELETE, pl_listnum, NULL);
  1500.         free(cd->lists[pl_listnum].name);
  1501.         if (cd->lists[pl_listnum].list != NULL)
  1502.             free(cd->lists[pl_listnum].list);
  1503.  
  1504.         for (i = pl_listnum; i < nlists; i++)
  1505.             cd->lists[i] = cd->lists[i + 1];
  1506.  
  1507.         shuf = xv_get(Workman_window1->shuffle, PANEL_VALUE);
  1508.         if (--nlists)
  1509.         {
  1510.             if (pl_listnum == nlists)
  1511.                 pl_listnum--;
  1512.             xv_set(ip->playlists, PANEL_LIST_SELECT, pl_listnum,
  1513.                 TRUE, NULL);
  1514.             switch_playlists(ip->playlists, NULL, NULL,
  1515.                 PANEL_LIST_OP_SELECT, NULL, pl_listnum);
  1516.         }
  1517.         else
  1518.         {
  1519.             pl_listnum = -1;
  1520.             free(cd->lists);
  1521.             cd->lists = NULL;
  1522.             switch_playlists(ip->playlists, NULL, NULL,
  1523.                 PANEL_LIST_OP_DESELECT, NULL, 0);
  1524.         }
  1525.         xv_set(Workman_window1->shuffle, XV_SHOW, FALSE,
  1526.             PANEL_CHOICE_STRINGS, "Normal", "Shuffle", NULL, NULL);
  1527.         for (i = 0; i < nlists; i++)
  1528.             xv_set(Workman_window1->shuffle, PANEL_CHOICE_STRING,
  1529.                 i + 2, cd->lists[i].name, NULL);
  1530.  
  1531.         if (shuf > pl_listnum + 1)
  1532.             shuf--;
  1533.         xv_set(Workman_window1->shuffle, PANEL_VALUE, shuf, XV_SHOW,
  1534.             TRUE, NULL);
  1535.         next_playmode_default(Workman_window1->shuffle, shuf, NULL);
  1536.     }
  1537. }
  1538.  
  1539. /*
  1540.  * Notify callback function for `button7'.
  1541.  */
  1542. void
  1543. plpopup_button7_notify_callback(item, event)
  1544.     Panel_item    item;
  1545.     Event        *event;
  1546. {
  1547.     add_playlist(item, event);
  1548. }
  1549.  
  1550. /*
  1551.  * Insert a track into the playlist.  This is the notify procedure for the
  1552.  * dynamically-built track number menu's items.
  1553.  */
  1554. void
  1555. insert_into_playlist(menu, item)
  1556.     Menu        menu;
  1557.     Menu_item    item;
  1558. {
  1559.     plpopup_objects *ip = Workman_plpopup;
  1560.     int    trackno;
  1561.  
  1562.     if (pl_listnum == -1)
  1563.         return;
  1564.  
  1565.     info_modified = 1;
  1566.  
  1567.     trackno = (int) xv_get(item, XV_KEY_DATA, 1234);
  1568.     if (pop_list == NULL)
  1569.         pop_list = (int *)malloc(sizeof (int) * 2);
  1570.     else
  1571.         pop_list = (int *)realloc(pop_list, sizeof (int) *
  1572.             (pop_listsize + 2));
  1573.     if (pop_list == NULL)
  1574.     {
  1575.         perror("malloc");
  1576.         exit(1);
  1577.     }
  1578.  
  1579.     xv_set(ip->playlist, PANEL_LIST_INSERT, pop_listsize,
  1580.         PANEL_LIST_STRING, pop_listsize,
  1581.         listentry(trackno - 1), PANEL_LIST_SELECT,
  1582.         pop_listsize, TRUE, NULL);
  1583.     xv_set(ip->delete, PANEL_INACTIVE, FALSE, NULL);
  1584.  
  1585.     pl_item = pop_listsize;
  1586.     pop_list[pop_listsize++] = trackno;
  1587.     pop_list[pop_listsize] = 0;
  1588.     cd->lists[pl_listnum].list = pop_list;
  1589. }
  1590.  
  1591. /*
  1592.  * Notify callback function for `playlists'.
  1593.  */
  1594. int
  1595. switch_playlists(item, string, client_data, op, event, row)
  1596.     Panel_item    item;
  1597.     char        *string;
  1598.     Xv_opaque    client_data;
  1599.     Panel_list_op    op;
  1600.     Event        *event;
  1601.     int        row;
  1602. {
  1603.     plpopup_objects *ip = Workman_plpopup;
  1604.     int    i, *thislist;
  1605.     
  1606.     switch(op) {
  1607.     case PANEL_LIST_OP_DESELECT:
  1608.         xv_set(ip->playlist, PANEL_LIST_DELETE_ROWS, 0,
  1609.             xv_get(ip->playlist, PANEL_LIST_NROWS), NULL);
  1610.         xv_set(ip->delete, PANEL_INACTIVE, TRUE, NULL);
  1611.         xv_set(ip->button5, PANEL_INACTIVE, TRUE, NULL);
  1612.         xv_set(ip->button6, PANEL_INACTIVE, TRUE, NULL);
  1613.         pop_list = NULL;
  1614.         pop_listsize = 0;
  1615.         pl_listnum = -1;
  1616.         pl_item = -1;
  1617.         break;
  1618.  
  1619.     case PANEL_LIST_OP_SELECT:
  1620.         xv_set(ip->button5, PANEL_INACTIVE, FALSE, NULL);
  1621.         xv_set(ip->button6, PANEL_INACTIVE, FALSE, NULL);
  1622.         /* If there's stuff in the list already (how?), delete it. */
  1623.         if (xv_get(ip->playlist, PANEL_LIST_NROWS) != 0)
  1624.             xv_set(ip->playlist, PANEL_LIST_DELETE_ROWS, 0,
  1625.                 xv_get(ip->playlist, PANEL_LIST_NROWS), NULL);
  1626.         thislist = cd->lists[row].list;
  1627.         if (thislist != NULL && thislist[0])
  1628.         {
  1629.             xv_set(ip->playlist, XV_SHOW, FALSE, NULL);
  1630.             for (i = 0; thislist[i]; i++)
  1631.                 xv_set(ip->playlist, PANEL_LIST_INSERT, i,
  1632.                     PANEL_LIST_STRING, i,
  1633.                     listentry(thislist[i] - 1), NULL);
  1634.             xv_set(ip->playlist, XV_SHOW, TRUE, PANEL_LIST_SELECT,
  1635.                 i - 1, TRUE, NULL);
  1636.             xv_set(ip->delete, PANEL_INACTIVE, FALSE, NULL);
  1637.             pop_list = thislist;
  1638.             pop_listsize = i;
  1639.             pl_item = 0;
  1640.         }
  1641.         else
  1642.         {
  1643.             pl_item = -1;
  1644.             pop_list = NULL;
  1645.             pop_listsize = 0;
  1646.             xv_set(ip->delete, PANEL_INACTIVE, TRUE, NULL);
  1647.         }
  1648.         pl_listnum = row;
  1649.         break;
  1650.  
  1651.     case PANEL_LIST_OP_VALIDATE:
  1652.     case PANEL_LIST_OP_DELETE:
  1653.         break;
  1654.     }
  1655.     return XV_OK;
  1656. }
  1657.  
  1658. /*
  1659.  * User-defined action for `abrepeat'.
  1660.  */
  1661. void
  1662. stop_repeating(item, value, event)
  1663.     Panel_item    item;
  1664.     int        value;
  1665.     Event        *event;
  1666. {
  1667.     was_repeating = 1;
  1668.     cur_lasttrack = cur_ntracks;
  1669. }
  1670.  
  1671. /*
  1672.  * Split the current track at the current position.
  1673.  */
  1674. void
  1675. split_track(item, event)
  1676.     Panel_item    item;
  1677.     Event        *event;
  1678. {
  1679.     int    listno;
  1680.  
  1681.     if (cur_frame < 1)
  1682.         return;
  1683.     
  1684.     if (! split_trackinfo(cur_frame))
  1685.         return;
  1686.  
  1687.     info_modified = 1;
  1688.  
  1689.     if (cur_track != -1 && pop_track > cur_track)
  1690.         pop_track++;
  1691.  
  1692.     fill_buttons();
  1693.     cleanout_lists();
  1694.     fill_lists();
  1695.     if (pl_listnum >= 0)
  1696.     {
  1697.         listno = pl_listnum;
  1698.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  1699.             PANEL_LIST_OP_DESELECT, NULL, pl_listnum);
  1700.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  1701.             PANEL_LIST_OP_SELECT, NULL, listno);
  1702.     }
  1703.  
  1704.     if (pop_track)
  1705.         xv_set(Workman_popup1->tracklist, PANEL_LIST_SELECT,
  1706.             pop_track - 1, TRUE, NULL);
  1707.  
  1708.     if (cur_track != -1)
  1709.         new_track(Workman_window1);
  1710. }
  1711.  
  1712. void
  1713. delete_track(item, event)
  1714.     Panel_item    item;
  1715.     Event        *event;
  1716. {
  1717.     int    listno;
  1718.  
  1719.     if (cur_track < 1)
  1720.         return;
  1721.     
  1722.     if (! remove_trackinfo(cur_track - 1))
  1723.         return;
  1724.     
  1725.     info_modified = 1;
  1726.  
  1727.     if (pop_track > cur_track)
  1728.         pop_track--;
  1729.     
  1730.     fill_buttons();
  1731.     cleanout_lists();
  1732.     fill_lists();
  1733.     if (pl_listnum >= 0)
  1734.     {
  1735.         listno = pl_listnum;
  1736.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  1737.             PANEL_LIST_OP_DESELECT, NULL, pl_listnum);
  1738.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  1739.             PANEL_LIST_OP_SELECT, NULL, listno);
  1740.     }
  1741.  
  1742.     if (pop_track)
  1743.     {
  1744.         if (pop_track == cur_track)
  1745.         {
  1746.             xv_set(Workman_popup1->trackname, PANEL_VALUE, "",
  1747.                 NULL);
  1748.             pop_track = 0;
  1749.         }
  1750.         xv_set(Workman_popup1->tracklist, PANEL_LIST_SELECT,
  1751.             pop_track - 1, TRUE, NULL);
  1752.     }
  1753.  
  1754.     new_track(Workman_window1);
  1755. }
  1756.  
  1757. void
  1758. index_scan(item, event)
  1759.     Panel_item    item;
  1760.     Event        *event;
  1761. {
  1762.     int    track, index;
  1763.  
  1764.     if (cur_cdmode != STOPPED)
  1765.     {
  1766.         change_mode(NULL, STOPPED, NULL);
  1767.         cur_cdmode = STOPPED;
  1768.         xv_set(Workman_window1->mode, PANEL_VALUE, STOPPED, NULL);
  1769.     }
  1770.  
  1771.     for (track = 1; track <= cd->ntracks; track++)
  1772.     {
  1773.         cur_frame = 0;
  1774.         index = 2;
  1775.         while (cur_frame = find_trkind(track, index, cur_frame))
  1776.         {
  1777.             cur_track = -1;
  1778.             split_track(item, event);
  1779.             index++;
  1780.         }
  1781.     }
  1782.  
  1783.     stop_cd();
  1784. }
  1785.  
  1786. /*
  1787.  * Called when the user quits.
  1788.  */
  1789. Notify_value
  1790. byebye(c, s)
  1791.     Notify_client    c;
  1792.     Destroy_status    s;
  1793. {
  1794.     if (s == DESTROY_CHECKING && cur_cdmode != EJECTED)
  1795.     {
  1796.         keep_settings(Workman_window1);
  1797.         if (info_modified)
  1798.         {
  1799.             xv_set(wannasave, XV_SHOW, TRUE, NULL);
  1800.             if (confirmsave)
  1801.                 save_config(NULL, NULL);
  1802.             info_modified = 0;
  1803.         }
  1804.     }
  1805.     else if (s == DESTROY_CLEANUP)
  1806.         return (notify_next_destroy_func(c, s));
  1807.  
  1808.     return (NOTIFY_DONE);
  1809. }
  1810.  
  1811. /*
  1812.  * Quit programmatically.  This will cause byebye() to be called, and
  1813.  * the main loop to exit.
  1814.  */
  1815. void
  1816. quit()
  1817. {
  1818.     xv_destroy_safe(Workman_window1->window1);
  1819. }
  1820.  
  1821. /*
  1822.  * Notify callback function for `playnewcds'.
  1823.  */
  1824. void
  1825. goodies_playnewcds_notify_callback(item, value, event)
  1826.     Panel_item    item;
  1827.     int        value;
  1828.     Event        *event;
  1829. {
  1830.     cur_playnew = value & 1;
  1831. }
  1832.  
  1833. /*
  1834.  * Handle SIGUSR1 (to pause the CD), SIGUSR2 (to play the CD), SIGTTIN
  1835.  * (to go back a track), SIGTTOU (forward a track), SIGEMT (eject CD), and
  1836.  * SIGQUIT (to stop the CD).
  1837.  */
  1838. Notify_value
  1839. sigusr1(client, sig, when)
  1840.     Notify_client        client;
  1841.     int            sig;
  1842.     Notify_signal_mode    when;
  1843. {
  1844.     if (cur_cdmode == PLAYING)
  1845.     {
  1846.         change_mode(NULL, PAUSED, NULL);
  1847.         cur_cdmode = PAUSED;
  1848.         xv_set(Workman_window1->mode, PANEL_VALUE, PAUSED, NULL);
  1849.     }
  1850.  
  1851.     return (NOTIFY_DONE);
  1852. }
  1853.  
  1854. Notify_value
  1855. sigusr2(client, sig, when)
  1856.     Notify_client        client;
  1857.     int            sig;
  1858.     Notify_signal_mode    when;
  1859. {
  1860.     if (cur_cdmode == STOPPED || cur_cdmode == PAUSED)
  1861.     {
  1862.         change_mode(NULL, PLAYING, NULL);
  1863.         cur_cdmode = PLAYING;
  1864.         xv_set(Workman_window1->mode, PANEL_VALUE, PLAYING, NULL);
  1865.     }
  1866.  
  1867.     return (NOTIFY_DONE);
  1868. }
  1869.  
  1870. Notify_value
  1871. sigquit(client, sig, when)
  1872.     Notify_client        client;
  1873.     int            sig;
  1874.     Notify_signal_mode    when;
  1875. {
  1876.     if (cur_cdmode == PLAYING || cur_cdmode == PAUSED)
  1877.     {
  1878.         change_mode(NULL, STOPPED, NULL);
  1879.         cur_cdmode = STOPPED;
  1880.         xv_set(Workman_window1->mode, PANEL_VALUE, STOPPED, NULL);
  1881.     }
  1882.  
  1883.     return (NOTIFY_DONE);
  1884. }
  1885.  
  1886. Notify_value
  1887. sigttin(client, sig, when)
  1888.     Notify_client        client;
  1889.     int            sig;
  1890.     Notify_signal_mode    when;
  1891. {
  1892.     change_mode(NULL, BACK, NULL);
  1893.  
  1894.     return (NOTIFY_DONE);
  1895. }
  1896.  
  1897. Notify_value
  1898. sigttou(client, sig, when)
  1899.     Notify_client        client;
  1900.     int            sig;
  1901.     Notify_signal_mode    when;
  1902. {
  1903.     change_mode(NULL, FORWARD, NULL);
  1904.  
  1905.     return (NOTIFY_DONE);
  1906. }
  1907.  
  1908. Notify_value
  1909. sigemt(client, sig, when)
  1910.     Notify_client        client;
  1911.     int            sig;
  1912.     Notify_signal_mode    when;
  1913. {
  1914.     change_mode(NULL, EJECTED, NULL);
  1915.     if (cur_cdmode == EJECTED)
  1916.         xv_set(Workman_window1->mode, PANEL_VALUE, 5, NULL);
  1917.  
  1918.     return (NOTIFY_DONE);
  1919. }
  1920.  
  1921. /*
  1922.  * Return the value of the "Play new CDs" button.
  1923.  */
  1924. get_playnew()
  1925. {
  1926.     return (xv_get(Workman_goodies->playnewcds, PANEL_VALUE));
  1927. }
  1928.  
  1929. /*
  1930.  * Send a signal to a running WorkMan and exit.
  1931.  */
  1932. send_signal(cmd, pidfile)
  1933.     char    *cmd;
  1934.     char    *pidfile;
  1935. {
  1936.     FILE    *fp;
  1937.     int    pid = 0;
  1938.  
  1939.     fp = fopen(pidfile, "r");
  1940.     if (fp == NULL)
  1941.     {
  1942.         perror(pidfile);
  1943.         exit(1);
  1944.     }
  1945.  
  1946.     fscanf(fp, "%d", &pid);
  1947.     if (pid == 0)
  1948.     {
  1949.         fprintf(stderr, "No pid in %s\n", pidfile);
  1950.         exit(1);
  1951.     }
  1952.  
  1953.     if (cmd[0] == 'b')
  1954.         kill(pid, SIGTTIN);
  1955.     else if (cmd[0] == 'p' && cmd[1] == 'l' || cmd[0] == 'g')
  1956.         kill(pid, SIGUSR2);
  1957.     else if (cmd[0] == 'f')
  1958.         kill(pid, SIGTTOU);
  1959.     else if (cmd[0] == 'p' && cmd[1] == 'a' || cmd[0] == 'm')
  1960.         kill(pid, SIGUSR1);
  1961.     else if (cmd[0] == 's')
  1962.         kill(pid, SIGQUIT);
  1963.     else if (cmd[0] == 'e')
  1964.         kill(pid, SIGEMT);
  1965.     else
  1966.     {
  1967.         fprintf(stderr, "Invalid command.  Use -h for help.\n");
  1968.         exit(1);
  1969.     }
  1970.  
  1971.     exit(0);
  1972. }
  1973.